import { /* MD5, */ TextCoder } from "./encryp";
import UtilTool from "./UtilTool";
// import * as lodash from "lodash";

export class Define {
    //长度宏定义
    static BYTE_LEN = 1;
    static INT_LEN = 4;
    static SORT_LEN = 2;
    static FLOAT_LEN = 4;
    static DOUBLE_LEN = 8;
    static NAME_LEN = 32									//名字长度
    static PASS_LEN = 33									//密码长度
    static EMAIL_LEN = 32									//邮箱长度
    static GROUP_LEN = 32									//社团长度
    static COMPUTER_ID_LEN = 33							    //机器序列
    static UNDER_WRITE_LEN = 32								//个性签名
}

export class ByteStream {
    private _buff: ArrayBuffer = null;
    private _dv: DataView = null;
    private _offset: number = 0;
    set Offset(v: number) {
        if (v > this.byteLength) {
            //越界异常
            throw new Error('当前buffer溢出' + this._offset +"-" + v );
        }
        this._offset = v;
    }
    get Offset() {
        return this._offset;
    }
    get byteLength() {
        return this._buff.byteLength;
    }
    get buffer (){
        return this._buff;
    }
    constructor(a: ArrayBuffer);
    constructor(size: number);
    constructor(d: any) {
        // UtilTool.printLog("typeof:::::::::::::::::::::::::")
        // UtilTool.printLog(d instanceof ArrayBuffer);
        // UtilTool.printLog("typeof:::::::::::::::::::::::::")
        // if (lodash.isNumber(d)) {
        if (typeof d === 'number') {
            this._buff = new ArrayBuffer(d);
        // } else if (lodash.isArrayBuffer(d)) {
        } else if (d instanceof ArrayBuffer) {
            this._buff = d
        } else {
            throw new Error('ByteStream 构造 错误的参数')
        }
        this._dv = new DataView(this._buff);
    }
    /**
     * 根据最高字节，检测当前位置是否要字节补齐
     * @param maxByteLen 结构体最高字节数
     */
    public checkByteOffset(maxByteLen:number = 4)
    {
        let offs = this.Offset%maxByteLen;
        if(offs != 0)
        {
            this.Offset+=(maxByteLen-offs);
        }
    }

    private _isOut(len:number){
        if(this._offset + len> this.byteLength ){
            throw new Error('当前buffer溢出');
        }
    }
    private _increment(len:number){
        if(this.Offset + len>= this.byteLength ){
            this.Offset =  this.byteLength;
            return ;
        }
        this.Offset += len;

    }

    readInt(littleEndian:boolean = true): number {
        this._isOut(Define.INT_LEN);
        let n = this._dv.getInt32(this.Offset, littleEndian);
        this._increment(Define.INT_LEN);
        return n;
    }

    readIntArray(len:number): Array<number> {
        let arr = [];
        for(var i= 0 ; i <len;i++){
            arr.push(this.readInt());
        }
        return arr;
    }
    writeInt(v: number,littleEndian:boolean = true) {
        this._isOut(Define.INT_LEN);
        this._dv.setInt32(this.Offset, v , littleEndian);
        this._increment(Define.INT_LEN);
    }



    readUint(littleEndian:boolean = true): number {
        this._isOut(Define.INT_LEN);
        let n = this._dv.getUint32(this.Offset, littleEndian);
        this._increment(Define.INT_LEN);
        return n;
    }

    readUintArray(len:number): Array<number> {
        let arr = [];
        for(var i= 0 ; i <len;i++){
            arr.push(this.readUint());
        }
        return arr;
    }
    writeUint(v: number,littleEndian:boolean = true) {
        this._isOut(Define.INT_LEN);
        this._dv.setUint32(this.Offset, v , littleEndian );
        this._increment(Define.INT_LEN);
    }


    readByte(): number {
        this._isOut(Define.BYTE_LEN);
        let n = this._dv.getUint8(this.Offset);
        this._increment(Define.BYTE_LEN);
        return n;
    }

    readByteArray(len: number,isAll:boolean = true):Array<number> {
        if (this.Offset + len > this.byteLength) {
            //越界异常
            throw new Error('当前buffer溢出');
        }
        let endOff = this.Offset + len;
        let arr = [];
        for (var i = 0; i < len; i++) {
            let ch = this.readByte();
            if(!isAll){
                if (Number(ch) === 0) {
                    break;
                }
            }    
            arr.push(ch);
        }
        this.Offset = Math.max(endOff,this.Offset);
        return arr;
    }

    writeByteArray(buf: ArrayBuffer, offset: number, len: number) {
        if (offset + len > buf.byteLength) {
            //越界异常
            throw new Error('目标buffer溢出');
        }
        if (this.Offset + len > this.byteLength) {
            //越界异常
            throw new Error('当前buffer溢出');
        }
        let dv = new ByteStream(buf);
        dv.Offset = offset;
        for (var i = 0; i < len; i++) {
            this.writeByte(dv.readByte());
        }
        return this;
    }


    writeByte(v: number) {
        this._isOut(Define.BYTE_LEN);
        this._dv.setUint8(this.Offset, v);
        this._increment(Define.BYTE_LEN);
    }

    readBoolean(): boolean {
        let n = this.readByte();
        return n > 0;
    }
    writeBoolean(v:boolean) {
       this.writeByte(v?1:0);
    }

    readBooleanArray(len:number): Array<boolean> {
        let arr = [];
        for(var i= 0 ; i <len;i++){
            arr.push(this.readBoolean());
        }
        return arr;
    }

    readSort(littleEndian:boolean = true): number {
        this._isOut(Define.SORT_LEN);
        let n = this._dv.getInt16(this.Offset, littleEndian);
        this._increment(Define.SORT_LEN);
        return n;
    }


    writeSort(v: number,littleEndian:boolean = true) {
        this._isOut(Define.SORT_LEN);
        this._dv.setInt16(this.Offset, v , littleEndian);
        this._increment(Define.SORT_LEN);
    }

    readUsort(littleEndian:boolean = true): number {
        this._isOut(Define.SORT_LEN);
        let n = this._dv.getUint16(this.Offset, littleEndian);
        this._increment(Define.SORT_LEN);
        return n;
    }


    readSortArray(len:number): Array<number> {
        let arr = [];
        for(var i= 0 ; i <len;i++){
            arr.push(this.readSort());
        }
        return arr;
    }

    writeUSort(v: number,littleEndian:boolean = true) {
        this._isOut(Define.SORT_LEN);
        this._dv.setUint16(this.Offset, v , littleEndian);
        this._increment(Define.SORT_LEN);
    }

    readUSortArray(len:number): Array<number> {
        let arr = [];
        for(var i= 0 ; i <len;i++){
            arr.push(this.readUsort());
        }
        return arr;
    }



    readFloat(littleEndian:boolean = true): number {
        this._isOut(Define.FLOAT_LEN);
        let n = this._dv.getFloat32(this.Offset, littleEndian);
        this._increment(Define.FLOAT_LEN);
        return n;
    }

    writeFloat(v: number,littleEndian:boolean = true) {
        this._isOut(Define.FLOAT_LEN);
        this._dv.setFloat32(this.Offset, v , littleEndian);
        this._increment(Define.FLOAT_LEN);
    }

    readDouble	(littleEndian:boolean = true): number {
        this._isOut(Define.DOUBLE_LEN);
        let n = this._dv.getFloat64(this.Offset, littleEndian);
        this._increment(Define.DOUBLE_LEN);
        return n;
    }

    writeDouble(v: number,littleEndian:boolean = true) {
        this._isOut(Define.DOUBLE_LEN);
        this._dv.setFloat64(this.Offset, v , littleEndian);
        this.Offset += Define.DOUBLE_LEN;
        this._increment(Define.DOUBLE_LEN);
    }
  
    reset(){
        for (var i = 0; i < this.byteLength; i++) {
            this._dv.setUint8(i, 0);
        }
        this.Offset = 0;
    }

    fill(v: number,len:number) {
        for (var i = 0; i < len; i++) {
            this.writeByte(v);
        }
    }
  

    readString(len: number, code: string = 'gb18030'): string {
        return TextCoder.decode(code,new Uint8Array( this.readByteArray(len,false)));
    }

    readStringArray(length:number, len: number, code: string = 'gb18030'): Array<string> {
        let arr:Array<string> = [];
        for(var i = 0;i<length ;i++){
            arr.push(TextCoder.decode(code,new Uint8Array( this.readByteArray(len,false))));
        }
        return arr;
    }

    writeString(str: string, len: number = 0, code: string = 'gb18030') {
        
        let strA = new Uint8Array(TextCoder.encode(code, str));
        if (len == 0) {
            len = strA.byteLength;
        }
        UtilTool.printLog("stringLen:"+len)
        if (this.Offset + len > this.byteLength) {
            //越界异常
            throw new Error('当前buffer溢出');
        }
        var endoff = this.Offset + len;
        this.writeByteArray(strA.buffer, 0, Math.min(strA.byteLength, len));
        this.Offset = Math.max(this.Offset,endoff);
    }







} 